
package com.turing.draw.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.turing.common.constants.CommonConstants;
import com.turing.common.entity.Context;
import com.turing.common.response.ResponseVO;
import com.turing.common.util.*;
import com.turing.draw.client.preprocessor.PreProcessorClient;
import com.turing.draw.client.procedure.ProcedureInnerService;
import com.turing.draw.client.reviewer.ReviewTaskInnerService;
import com.turing.draw.client.reviewer.ReviewerOpClient;
import com.turing.draw.dao.fileTaskMapper;
import com.turing.draw.enums.FileStatusEnum;
import com.turing.draw.enums.FileTypeEnum;
import com.turing.draw.enums.OcrPageTaskStatusEnum;
import com.turing.draw.enums.TaskStatusEnum;
import com.turing.draw.model.domain.DrawTask;
import com.turing.draw.model.domain.FileImage;
import com.turing.draw.model.domain.FileTask;
import com.turing.draw.model.domain.OcrPageTask;
import com.turing.common.entity.ParseTableVO;
import com.turing.draw.service.*;
import com.turing.draw.utils.TableUtil;
import com.turing.draw.vo.in.OcrResultEntity;
import com.turing.draw.vo.in.TextSearchVO;
import com.turing.draw.vo.out.FileTaskVo;
import com.turing.draw.vo.out.ParaInfoVO;
import com.turing.orm.handler.DateTableNameParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.CollectionUtils;

import java.io.File;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;


/**
 * @Description 服务类实现
 * @Author livin
 * @Date 2021-11-04
 */
@Service
public class FileTaskServiceImpl extends ServiceImpl<fileTaskMapper, FileTask> implements FileTaskService {

    private Logger logger = LoggerFactory.getLogger(FileTaskServiceImpl.class);

    @Autowired
    private fileTaskMapper fileTaskMapper;

    @Value("${fdfs.domain}")
    private String FDFS_DOMAIN;

    @Autowired
    private OcrPageTaskService ocrPageTaskService;

    @Autowired
    private DrawTaskService drawTaskService;

    @Autowired
    private CorrectOCRAnalyzeJsonService correctOCRAnalyzeJsonService;

    @Autowired
    private FileImageService fileImageService;

    @Autowired
    private ProcedureInnerService procedureInnerService;

    @Autowired
    private PreProcessorClient preProcessorClient;

    @Autowired
    private ReviewTaskInnerService reviewTaskInnerService;

    @Autowired
    private ReviewerOpClient reviewerOpClient;

    @Override
    public Integer getTaskStatusById(String taskSn ) {
        FileTask fileTask = lambdaQuery().eq(FileTask::getTaskSn, taskSn)
            .eq(FileTask::getIsDel,0)
            .select(FileTask::getFileStatus)
            .one();
        return Optional.ofNullable(fileTask).map(FileTask::getFileStatus).orElse(FileStatusEnum.NOTEXIST.getCode());
    }

    /***
      * @MethodName createFileTask
      * @Description  创建文件任务
      * @param: templateId
      * @param: drawTask
      * @param: filePath  
      */
    @Override
    @Transactional
    public void createFileTask(String templateId,DrawTask drawTask, String filePath) {

        List<String> fileTypes = Collections.singletonList(FileTypeEnum.PDF.getName());
        List<String> photoTypes = Arrays.asList("jpg","tif","tiff","jpeg","png","bmp");

        File file = new File(filePath);
        String fileUrl = FdfsUtils.uploadFile(file);
        String fileName = file.getName();
        String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
        fileName = fileName.substring(0, fileName.lastIndexOf(".")).replaceAll(" ","");
        String parentTaskSn = drawTask.getTaskSn();
        SnowflakeIdWorker snowflakeIdWorker = new SnowflakeIdWorker(0, 1);
        FileTask fileTask = FileTask.builder()
                .taskSn(String.valueOf(snowflakeIdWorker.nextId()))
                .parentTaskSn(parentTaskSn)
                .fileName(fileName)
                .fileType(fileExt)
                .fileUrl(fileUrl)
                .fileExt(fileExt)
                .templateId(drawTask.getTemplateId())
                .templateGroup(drawTask.getTemplateGroup())
                .createdBy(Context.getTokenContext().getUserId())
                .fileStatus(fileExt.equals(FileTypeEnum.JPG.getName()) ? FileStatusEnum.PRETASKFINISHED.getCode() : FileStatusEnum.UPLOADED.getCode()).build();

        int totalPage = 0;
        fileTask.setBelongsElec(0);
        if(fileExt.equals("jpg")){
            fileTask.setTotalPage(1);
        }
        logger.info("======> 判断pdf总页数");
        if (fileExt.equals("pdf")) {
            totalPage = PdfUtils.countPDFPage2(file);
            fileTask.setTotalPage(totalPage);
            logger.info("======> 判断pdf中是否包含图片,pdf总页数为："+totalPage);
            //r-GSAB_FXQRD特殊场景分销确认单直接走解析后再去走后处理
            if(!PdfBoxUtils.hasImage(filePath) || "r-GSAB_FXQRD".equals(templateId)){
                fileTask.setBelongsElec(1);
                fileTask.setPdfUrl(fileUrl);
            }
        }

        if(templateId.equals("101")){
            fileTask.setBelongsElec(2);
            fileTask.setPdfUrl(fileUrl);
        }
        File f = new File(file.toURI());
        logger.info("deleting transFile:"+f.delete());
        //保存fileTask
        save(fileTask);
        String taskSn = fileTask.getTaskSn();
        for (int i = 0; i < totalPage; i++) {
            if( fileTypes.contains(fileTask.getFileType())){
                OcrPageTask ocrPageTask = OcrPageTask.builder().parentTaskSn(parentTaskSn)
                    .taskSn(taskSn)
                    .templateId(fileTask.getTemplateId())
                    .ocrPageTaskStatus(OcrPageTaskStatusEnum.CREATED.getCode())
                    .templateGroup(fileTask.getTemplateGroup())
                    .pageNo(i)
                    .retryCount(0)
                    .build();
                if(totalPage == 1){
                    ocrPageTask.setSinglePage(1);
                }
                FileImage fileImage = FileImage.builder().parentTaskSn(parentTaskSn).taskSn(taskSn).pageNo(i).build();
                DateTableNameParser.setTaskSn(Long.parseLong(taskSn));
                fileImageService.save(fileImage);
                if(fileTask.getBelongsElec() == 0){
                    ocrPageTaskService.save(ocrPageTask);
                }
            }
        }

        if(photoTypes.contains(fileExt) && !templateId.equals("101")){
            logger.info("init ocr page task for photo..");
            OcrPageTask ocrPageTask = OcrPageTask.builder().parentTaskSn(parentTaskSn)
                    .taskSn(taskSn)
                    .templateId(fileTask.getTemplateId())
                    .ocrPageTaskStatus(fileExt.equals("jpg") ? OcrPageTaskStatusEnum.QUEUING.getCode() : OcrPageTaskStatusEnum.CREATED.getCode() )
                    .templateGroup(fileTask.getTemplateGroup())
                    .pageNo(0)
                    .retryCount(0)
                    .imageUrl(fileUrl)
                    .build();
            ocrPageTask.setSinglePage(1);
            FileImage fileImage = FileImage.builder().parentTaskSn(parentTaskSn).taskSn(taskSn).pageNo(0).imageUrl(fileUrl).build();
            DateTableNameParser.setTaskSn(Long.parseLong(taskSn));
            fileImageService.save(fileImage);
            ocrPageTaskService.save(ocrPageTask);
        }

    }

    @Override
    public String queryParentTask(String childTaskSn) {

        FileTask fileTask = fileTaskMapper.selectById(childTaskSn);
        return Optional.ofNullable(fileTask).filter(f->!StringUtils.isEmpty(f.getTaskSn())).map(FileTask::getTaskSn).orElse(CommonConstants.EMPTY_STRING);

    }

    @Override
    public Integer getTaskVersion(String parentTaskSn) {
        return 0;
    }

    @Override
    public List<FileTask> getChildTasks(String taskSn) {

        return lambdaQuery().eq(FileTask::getParentTaskSn,taskSn)
                .eq(FileTask::getIsDel,0)
                .list();

    }

    public List<ParaInfoVO> initParaInfo(TextSearchVO textSearchVO, FileTask task) {
        List<ParaInfoVO> paraInfoVOS = new ArrayList<>();
        if (null != task && !StringUtils.isEmpty(task.getJSONUrl())) {
            //获取ocr文本
            String json = FileUtils.loadJson(FDFS_DOMAIN+task.getJSONUrl());
            JSONArray jsonArray = JSON.parseArray(json);
            for (Object pageInfo : jsonArray) {
                if (null != pageInfo) {
                    JSONObject pageObj = JSONObject.parseObject(pageInfo.toString());
                    if (null != pageObj.getString("paragraphs")) {
                        JSONArray linesArr = JSON.parseArray(pageObj.getString("paragraphs"));
                        if (!CollectionUtils.isEmpty(linesArr)) {
                            for (Object linesObj : linesArr) {
                                if (null != linesObj) {
                                    JSONObject linesJson = JSONObject.parseObject(linesObj.toString());
                                    if (null != linesJson.get("lines")) {
                                        JSONArray lineArr = JSON.parseArray(linesJson.getString("lines"));
                                        if (!CollectionUtils.isEmpty(lineArr)) {
                                            for (Object lineObj : lineArr) {
                                                if (!StringUtils.isEmpty(lineObj.toString())) {
                                                    JSONObject lineJson = JSON.parseObject(lineObj.toString());
                                                    if (!StringUtils.isEmpty(lineJson.getString("objContent"))) {
                                                        String objContent = lineJson.getString("objContent");
                                                        if (objContent.contains(textSearchVO.getText())) {
                                                            ParaInfoVO paraInfoVO = new ParaInfoVO();
                                                            paraInfoVO.setLineNo(lineJson.getInteger("lineNo"));
                                                            paraInfoVO.setLineId(lineJson.getString("lineId"));
                                                            paraInfoVO.setDocId(pageObj.getString("docID"));
                                                            paraInfoVO.setPageNo(pageObj.getInteger("pageNo"));
                                                            paraInfoVO.setText(textSearchVO.getText());
                                                            String expandText = TextUtils.expandTextLimit(textSearchVO.getText(),objContent,5,5);
                                                            paraInfoVO.setExpandText(expandText);
                                                            paraInfoVOS.add(paraInfoVO);
                                                            if(paraInfoVOS.size()==20){
                                                                return paraInfoVOS;
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        return paraInfoVOS;
    }


    @Override
    public FileTask getOvertimeTaskByStatus(Integer status) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String format = LocalDateTime.now().format(formatter);
        return  lambdaQuery()
                .select(FileTask::getParentTaskSn, FileTask::getTaskSn, FileTask::getForecastRetryCount, FileTask::getPreProcessorRetryCount )
                .eq(FileTask::getFileStatus, status)
                .apply("UNIX_TIMESTAMP(pre_processor_warning_time) < UNIX_TIMESTAMP('" + format + "')")
                .eq(FileTask::getIsDel, 0)
                .last("limit 1")
                .one();
    }

    @Override
    public FileTask getOvertimeForecastTaskByStatus(Integer status) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String format = LocalDateTime.now().format(formatter);
        return  lambdaQuery()
                .select(FileTask::getParentTaskSn, FileTask::getTaskSn, FileTask::getForecastRetryCount, FileTask::getPreProcessorRetryCount )
                .eq(FileTask::getFileStatus, status)
                .apply("UNIX_TIMESTAMP(forecast_warning_time) < UNIX_TIMESTAMP('" + format + "')")
                .eq(FileTask::getIsDel, 0)
                .last("limit 1")
                .one();
    }

    @Override
    public FileTask getFileTaskByStatus(Integer status) {
        return lambdaQuery()
                .eq(FileTask::getFileStatus, status)
                .orderByDesc(FileTask::getTemplateGroup)
                .orderByDesc(FileTask::getCreatedTime)
                .last("limit 1").one();
    }

    @Override
    public FileTask getAnalysisTask() {

        return lambdaQuery()
                .and(queryWrapper->queryWrapper.eq(FileTask::getFileStatus, FileStatusEnum.PRETASKFINISHED.getCode())
                        .isNotNull(FileTask::getPdfUrl)
                        .eq(FileTask::getBelongsElec,1))
                .or(queryWrapper->queryWrapper.eq(FileTask::getFileStatus, FileStatusEnum.PRETASKFINISHED.getCode())
                        .in(FileTask::getFileType,Arrays.asList(FileTypeEnum.DOC.getName(),FileTypeEnum.DOCX.getName(),FileTypeEnum.TXT.getName()))
                        .isNotNull(FileTask::getPdfUrl))
                .orderByDesc(FileTask::getParentTaskSn)
                .orderByDesc(FileTask::getTemplateGroup)
                .orderByDesc(FileTask::getCreatedTime)
                .last("limit 1").one();
    }

    @Override
    public boolean lockPreProcessorTask(String domain, String taskSn) {
        return lambdaUpdate()
                .eq(FileTask::getTaskSn, taskSn)
                .set(FileTask::getFileStatus, FileStatusEnum.PRETASKPROCESSING.getCode())
                .set(FileTask::getPreProcessorWarningTime, LocalDateTime.now().plusMinutes(10))
                .set(FileTask::getPreProcessorDomain, domain)
                .update();
    }

    @Override
    public boolean lockForecastTask(String domain, String taskSn) {
        return lambdaUpdate()
                .eq(FileTask::getTaskSn, taskSn)
                .set(FileTask::getFileStatus, FileStatusEnum.FORECASTTASKPROCESSING.getCode())
                .set(FileTask::getPreProcessorWarningTime, LocalDateTime.now().plusMinutes(10))
                .set(FileTask::getPreProcessorDomain, domain)
                .update();
    }

    @Override
    public boolean unLockForecastTask(String taskSn) {

        FileTask fileTask = getById(taskSn);
        int retryCount = fileTask.getForecastRetryCount();
        int status;
        if(retryCount > 1){
            status = FileStatusEnum.FAILED.getCode();
            tasksFailed(fileTask.getParentTaskSn(),"10005:预测失败");
        }else{
            status = FileStatusEnum.OCRTASKFINISHED.getCode();
        }
        return lambdaUpdate().eq(FileTask::getTaskSn, taskSn)
                .set(FileTask::getFileStatus, status)
                .set(FileTask::getForecastRetryCount, fileTask.getForecastRetryCount()+1)
                .update();

    }

    @Override
    public boolean lockAnalysisTask(String domain, String taskSn) {
        return lambdaUpdate()
                .eq(FileTask::getTaskSn, taskSn)
                .set(FileTask::getFileStatus, FileStatusEnum.OCRTASKPROCESSING.getCode())
                .set(FileTask::getAnalysisWarningTime, LocalDateTime.now().plusMinutes(10))
                .set(FileTask::getAnalysisDomain, domain)
                .update();
    }

    @Override
    public boolean unLockAnalysisTask(String taskSn) {

        FileTask fileTask = getById(taskSn);
        int retryCount = fileTask.getAnalysisRetryCount();
        int status;
        if(retryCount > 1){
            status = FileStatusEnum.FAILED.getCode();
            tasksFailed(fileTask.getParentTaskSn(),"10007:解析失败");
        }else{
            status = FileStatusEnum.PRETASKFINISHED.getCode();
        }
        return lambdaUpdate().eq(FileTask::getTaskSn, taskSn)
                .set(FileTask::getFileStatus, status)
                .set(FileTask::getAnalysisRetryCount, fileTask.getAnalysisRetryCount()+1)
                .update();

    }


    @Override
    public List<FileTask> getTasksByParentTaskSn(String parentTaskSn) {
        return list(new LambdaQueryWrapper<FileTask>()
                .eq(FileTask::getParentTaskSn, parentTaskSn)
                .eq(FileTask::getIsDel, 0));
    }

    @Override
    public boolean updateTaskByStatusAndId(String taskSn,Integer status) {
        return updateById(FileTask.builder().taskSn(taskSn).fileStatus(status).build());
    }

    @Override
    public boolean analysisFinished(String taskSn, String ocrJsonUrl) {

        String JSONText = FileUtils.loadJson(FDFS_DOMAIN + ocrJsonUrl);
        JSONText = JSONText.replaceAll(" ","").replaceAll("　","").replaceAll("  ","");
//        JSONText = JSONText.replaceAll(" ","").replaceAll("　","").replaceAll("  ","");
        JSONArray jsonArray = JSONArray.parseArray(JSONText.trim());
        StringBuilder cleanBuilder = new StringBuilder();
        for (Object obj : jsonArray) {
            OcrResultEntity.PageEntity pageEntity = JSONObject.parseObject(obj.toString(),OcrResultEntity.PageEntity.class);
            List<OcrResultEntity.PageEntity.LineEntity> lineList = pageEntity.getLineList();
            if(Tools.isNotEmpty(lineList)){
                for (OcrResultEntity.PageEntity.LineEntity lineEntity : lineList) {
                    String objContent = lineEntity.getObjContent();
                    if(StringUtils.isNotEmpty(objContent)){
                        if(lineEntity.getObjType().equals("table")){
                            objContent = objContent.replaceAll(":","");
                        }
                        cleanBuilder.append(objContent);
                    }
                }
            }
        }

        List<ParseTableVO> tables = new ArrayList<>();
        try{
            logger.debug("===========> 开始进行表格处理 <===============");
            tables = TableUtil.handleTables(jsonArray);
            logger.debug("===========> 表格处理完成 <===============");
        }catch (Exception e) {
            logger.error("表格数据处理失败");
            e.printStackTrace();
        }

        String tableJsonUrl = FdfsUtils.uploadBytes(JSONArray.toJSONString(tables));
        String cleanText = cleanBuilder.toString();
        String cleanTextUrl = FdfsUtils.uploadBytes(cleanText);
        String mergedJSONUrl = uploadMergedOcrResult(taskSn, jsonArray,  fileImageService);

        lambdaUpdate().eq(FileTask::getTaskSn, taskSn)
            .set(FileTask::getJSONUrl, mergedJSONUrl)
            .set(FileTask::getOcrJsonUrl,ocrJsonUrl)
            .set(FileTask::getFileStatus, FileStatusEnum.OCRTASKFINISHED.getCode())
            .set(FileTask::getCleanTextUrl,cleanTextUrl)
            .set(FileTask::getTableJsonUrl,tableJsonUrl)
            .update();
        return doRuleProcess(getById(taskSn));

    }

    @Override
    public String uploadMergedOcrResult(String taskSn, JSONArray jsonArray, FileImageService fileImageService) {

        FileUtils.doTransOCRJsonArr(jsonArray);
        correctOCRAnalyzeJsonService.doInterpolation(jsonArray);
        correctOCRAnalyzeJsonService.populatePosInfo(jsonArray);
        logger.info("finish json processor");

        jsonArray.forEach(
            pageEntity->{
                JSONObject jsonObject = JSONObject.parseObject(pageEntity.toString());
                Integer pageNo = jsonObject.getInteger("pageNo");
                String pageJsonUrl = FdfsUtils.uploadBytes(jsonObject.toJSONString());
                boolean b = fileImageService.saveJsonUrl(taskSn, pageNo, pageJsonUrl);
                logger.info("upload page json to fdfs,result is:"+b+",pageNo is:"+pageNo+",json is:"+pageJsonUrl);
            }
        );
        logger.info("start upload json..length:"+jsonArray.toJSONString().length());
        String mergedJSONUrl = FdfsUtils.uploadBytes(jsonArray.toJSONString());
        logger.info("upload json to fdfs,url is:"+mergedJSONUrl);
        return mergedJSONUrl;
    }

    @Override
    public boolean savePdfUrl(String pdfUrl, String taskSn) {

        return lambdaUpdate().eq(FileTask::getTaskSn,taskSn).set(FileTask::getPdfUrl,pdfUrl).update();

    }

    @Override
    public String getParentTaskSn(String taskSn) {
        FileTask fileTask = lambdaQuery().eq(FileTask::getTaskSn, taskSn).select(FileTask::getParentTaskSn).one();
        return Optional.ofNullable(fileTask).map(FileTask::getParentTaskSn).orElse("");
    }

    @Override
    public boolean allFileTasksFailed(String parentTaskSn) {
        return lambdaUpdate().eq(FileTask::getParentTaskSn, parentTaskSn)
                .set(FileTask::getFileStatus, FileStatusEnum.FAILED.getCode()).update();
    }


    @Override
    public boolean tasksFailed(String parentTaskSn,String errorMessage) {
        ocrPageTaskService.tasksFailed(parentTaskSn);
        drawTaskService.updateTaskByStatus(parentTaskSn,TaskStatusEnum.FAILED.getCode());
        preProcessorClient.taskFailed(parentTaskSn);
        procedureInnerService.taskFailed(parentTaskSn,errorMessage);
        return allFileTasksFailed(parentTaskSn);
    }



    @Override
    public boolean forecastFinished(String parentTaskSn) {

        DrawTask drawTask = drawTaskService.lambdaQuery().select(DrawTask::getFileNumbers).eq(DrawTask::getTaskSn, parentTaskSn).last("limit 1").one();
        Integer finishCount = lambdaQuery().eq(FileTask::getParentTaskSn, parentTaskSn)
                .eq(FileTask::getFileStatus, FileStatusEnum.FORECASTTASKFINISHED.getCode())
                .eq(FileTask::getIsDel, 0)
                .count();
        return drawTask.getFileNumbers().equals(finishCount);

    }

    @Override
    public boolean ocrFinished(String parentTaskSn) {

        DrawTask drawTask = drawTaskService.lambdaQuery().select(DrawTask::getFileNumbers).eq(DrawTask::getTaskSn, parentTaskSn).last("limit 1").one();
        Integer finishCount = lambdaQuery().eq(FileTask::getParentTaskSn, parentTaskSn)
                .eq(FileTask::getFileStatus, FileStatusEnum.OCRTASKFINISHED.getCode())
                .eq(FileTask::getIsDel, 0)
                .count();
        return drawTask.getFileNumbers().equals(finishCount);

    }

    @Override
    public boolean saveTotalPage(String taskSn, Integer totalPage) {
        return lambdaUpdate().eq(FileTask::getTaskSn,taskSn)
                .set(FileTask::getTotalPage,totalPage).update();
    }

    @Override
    public boolean doRuleProcess(FileTask fileTask) {
        String parentTaskSn = fileTask.getParentTaskSn();
        if(ocrFinished(parentTaskSn)){
            logger.info("ocr finished");
            String templateId = fileTask.getTemplateId();
            if(needCallPostProcess(templateId)){
                logger.info("starting do rule process");
                if(!fileTask.getCreatedBy().equals(34)){
                    reviewerOpClient.populateEmptyElements(parentTaskSn,templateId);
                    if(TransactionSynchronizationManager.isActualTransactionActive()) {
                        // 当前存在事务-存在a在修改a表的时候，b方法也需要去修改a表，但是这时候a表锁没有释放会导致锁表异常（分布式锁也可以）
                        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
                            // 事务提交后执行后处理
                            @Override
                            public void afterCommit() {
                                logger.info("starting do reviewTaskInnerService.runScriptsTask 001");
                                ResponseVO<String> res = reviewTaskInnerService.runScriptsTask(parentTaskSn);
                                if(res != null && res.getData().equals("ok")){
                                    taskFinish(parentTaskSn);
                                }else {
                                    tasksFailed(parentTaskSn, "10005:后处理失败");
                                }
                            }});
                    } else {
                        logger.info("starting do reviewTaskInnerService.runScriptsTask 002");
                        ResponseVO<String> res = reviewTaskInnerService.runScriptsTask(parentTaskSn);
                        if(res != null && res.getData().equals("ok")){
                            taskFinish(parentTaskSn);
                        }else {
                            tasksFailed(parentTaskSn, "10005:后处理失败");
                        }
                    }
                }else{
                    taskFinish(parentTaskSn);
                }
            }else{
                // update task record taskStatus
                boolean updateRecord = drawTaskService.updateTaskByStatus(parentTaskSn,TaskStatusEnum.OCRFINISHED.getCode());
                logger.info("update task record,status is:"+updateRecord);
                procedureInnerService.OCRTaskFinished(parentTaskSn);
            }
        }
        return true;
    }

    @Override
    public FileTask getForecastTask(String templates) {

        String[] templateStr = templates.split(",");

        return lambdaQuery()
            .eq(FileTask::getFileStatus, FileStatusEnum.OCRTASKFINISHED.getCode())
            .and(i -> i.ne(FileTask::getParentFileTaskSn, 0).or().isNull(FileTask::getParentFileTaskSn))
//            .in(FileTask::getTemplateId, templateStr)
            .notLike(FileTask::getTemplateId,"r-")
            .orderByDesc(FileTask::getTemplateGroup)
            .orderByDesc(FileTask::getCreatedTime)
            .last("limit 1").one();
    }

    @Override
    public FileTask getCurriculumVitaeTask() {

        return lambdaQuery()
                .eq(FileTask::getFileStatus, FileStatusEnum.PRETASKFINISHED.getCode())
                .eq(FileTask::getBelongsElec,2)
                .orderByDesc(FileTask::getParentTaskSn)
                .orderByDesc(FileTask::getTemplateGroup)
                .orderByDesc(FileTask::getCreatedTime)
                .last("limit 1").one();

    }

    @Override
    public FileTask getTaskByTaskSn(String taskSn) {
        return lambdaQuery()
                .eq(FileTask::getTaskSn, taskSn)
                .eq(FileTask::getIsDel, "0")
                .one();
    }

    @Override
    public List<FileTask> getSonTaskByParentFileTaskSn(String parentFileTaskSn) {


        return lambdaQuery()
                .eq(FileTask::getParentFileTaskSn, parentFileTaskSn)
                .eq(FileTask::getIsDel, "0")
                .list();
    }

    @Override
    public boolean updateTaskTemplateIdById(String taskSn, String templateId) {
        return lambdaUpdate()
                .eq(FileTask::getTaskSn, taskSn)
                .eq(FileTask::getIsDel, "0")
                .set(FileTask::getTemplateId, templateId)
                .update();
    }

    private void taskFinish(String parentTaskSn) {
        lambdaUpdate().eq(FileTask::getParentTaskSn,parentTaskSn).set(FileTask::getFileStatus,FileStatusEnum.FORECASTTASKFINISHED.getCode()).update();
        boolean taskFinished = drawTaskService.updateTaskByStatus(parentTaskSn, TaskStatusEnum.FINISHED.getCode());
        logger.info("post process finished ,update task record,status is:" + taskFinished);
        procedureInnerService.forecastFinished(parentTaskSn);
    }

    private boolean needCallPostProcess(String templateId) {
        return templateId.startsWith("r-");
    }

    @Override
    public Integer countFilesByParentTaskSnAndStatus(String parentTaskSn, Integer status) {
        return count(new LambdaQueryWrapper<FileTask>().eq(FileTask::getParentTaskSn, parentTaskSn)
                .eq(FileTask::getFileStatus, status)
                .eq(FileTask::getIsDel, 0));
    }

    @Override
    public boolean saveJSONTextByTaskSn(String taskSn,String jsonUrl,String ocrJsonUrl,String cleanTextUrl,String tableJsonUrl) {
        return  lambdaUpdate()
                .eq(FileTask::getTaskSn, taskSn)
                .set(FileTask::getJSONUrl, jsonUrl)
                .set(FileTask::getOcrJsonUrl,ocrJsonUrl)
                .set(FileTask::getCleanTextUrl,cleanTextUrl)
                .set(FileTask::getTableJsonUrl,tableJsonUrl)
                .update();
    }

    @Override
    public boolean finishReview(String taskSn) {

        boolean updated = updateTaskByStatusAndId(taskSn, FileStatusEnum.REVIEWFINISHED.getCode());
        if(updated){
            // calculate if all task finished
            if(lambdaQuery().ne(FileTask::getFileStatus,FileStatusEnum.REVIEWFINISHED.getCode()).eq(FileTask::getTaskSn,taskSn).count() == 0){
                 procedureInnerService.finishReview(getParentTaskSn(taskSn));
            }
            return true;
        }
        return false;

    }

    @Override
    public List<FileTaskVo> getTemplateIdListByDrawTaskSn(String drawTaskSn) {
        LambdaQueryWrapper<FileTask> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.select(FileTask::getTaskSn,
                FileTask::getParentTaskSn,
                FileTask::getTemplateId,
                FileTask::getParentFileTaskSn)
                .eq(FileTask::getParentTaskSn, drawTaskSn);

        List<FileTask> fileTaskList = this.list(lambdaQueryWrapper);

        if (CollectionUtils.isEmpty(fileTaskList)) {
            return Collections.emptyList();
        }

        // 混合场景下, 存在子级的file_task, 所以需要关联parent_file_task_sn字段查出
        List<FileTask> mixedSubsetFileTaskList = new ArrayList<>();
        for (FileTask fileTask : fileTaskList) {
            if ("0".equals(fileTask.getParentFileTaskSn())) {
                mixedSubsetFileTaskList = this.list(Wrappers.<FileTask>lambdaQuery()
                        .select(FileTask::getTaskSn,
                                FileTask::getParentTaskSn,
                                FileTask::getTemplateId,
                                FileTask::getParentFileTaskSn)
                        .eq(FileTask::getParentFileTaskSn, fileTask.getTaskSn()));
            }
        }
        fileTaskList.addAll(mixedSubsetFileTaskList);

        List<FileTaskVo> filetTaskResultVO = new ArrayList<>();

        fileTaskList.forEach(i -> {
            FileTaskVo fileTaskVo = new FileTaskVo();
            BeanUtils.copyProperties(i, fileTaskVo);
            filetTaskResultVO.add(fileTaskVo);
        });
        return filetTaskResultVO;
    }
}
